package com.ruoyi.system.netty;

//import cn.hniot.common.utils.SpringUtils;
//import cn.hniot.iot.common.ConvertCode;
//import cn.hniot.iot.common.ElectricityMeterUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.service.impl.SendInstructsServiceImpl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;

@Slf4j
public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
    private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static final SendInstructsServiceImpl sis = SpringUtils.getBean("sendInstructsService");

//    SendInstructsService sendInstructsService;
    /**
     * 从客户端收到新的数据时，这个方法会在收到消息时被调用x
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception, IOException
    {
        String str = (String)msg;
        log.info("channelRead:read msg:"+msg);
        //将收到的消息发送给回调处理方法
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        sis.callbackInstructResultMsg(clientIp,str);
    }

    private void writeMessage(ChannelHandlerContext ctx, byte[] obj) {
        ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
        bufff.writeBytes(obj);//对接需要16进制

        ctx.writeAndFlush(bufff).addListener(new ChannelFutureListener() { //获取当前的handle
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                StringBuilder sb = new StringBuilder("");

                if (future.isSuccess()) {

                    log.info(sb.toString() + "回写成功.");
                } else {
                    log.error(sb.toString() + "回写失败.");
                }
            }
        });
    }

    /**
     * 从客户端收到新的数据、读取完成时调用
     *
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws IOException
    {
        log.info("channelReadComplete");

        ctx.flush();
    }

    /**
     * 当出现 Throwable 对象才会被调用，即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws IOException
    {
        log.info("exceptionCaught");
        cause.printStackTrace();
        ctx.close();//抛出异常，断开与客户端的连接
    }

    /**
     * 客户端与服务端第一次建立连接时 执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception, IOException
    {
        super.channelActive(ctx);
        ctx.channel().read();
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        //更新网关状态
//        sendInstructsService.handleGateWayStatus(clientIp,null,true);
        //此处不能使用ctx.close()，否则客户端始终无法与服务端建立连接
        log.info("channelActive:"+clientIp+ctx.name());
        log.info("clientIp:"+clientIp +":"+insocket.getPort());
        //添加通道到全局
        channels.add(ctx.channel());

    }

    /**
     * 客户端与服务端 断连时 执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception, IOException
    {
        //断开连接从通道组中移出
        channels.remove(ctx.channel());
        super.channelInactive(ctx);
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        //更新网关状态
//        sendInstructsService.handleGateWayStatus(clientIp,null,false);
        ctx.close(); //断开连接时，必须关闭，否则造成资源浪费，并发量很大情况下可能造成宕机
        log.info("channelInactive:"+clientIp);
    }

    /**
     * 服务端当read超时, 会调用这个方法
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception, IOException
    {
        super.userEventTriggered(ctx, evt);
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        ctx.close();//超时时断开连接
        log.info("userEventTriggered:"+clientIp);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
        log.info("channelRegistered");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
        log.info("channelUnregistered");
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception{
        log.info("channelWritabilityChanged");
    }

    public static ChannelGroup getChannels() {
        return channels;
    }

}
